#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <strings.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>     /*包含close函数，关闭套接字文件描述符*/

#define SENDBUFFERSIZE  1024

/**
 * @brief         满足:1.向服务器发送信息。
 *                     2.同时接收服务器信息
 * 
 * @attention
 */

/**
 * @brief         子线程用于接收服务器端的数据，打印到终端
 * 
 * @param         arg: socket file descriptor
 * @return        void*
 * @attention
 */
void *client_recv_fun(void *arg)
{
    int sockfd = *((int *)arg);

    char buffer[SENDBUFFERSIZE];
    int nbytes;

    /*循环接收服务端发送来的数据，打印在终端上*/
    while(1)
    {
        nbytes = recv(sockfd, buffer, SENDBUFFERSIZE, 0);
        if(nbytes == -1)
        {
            printf("[system:recv error!]\n");
            continue;
        }
        
        /*接收到了正常的字符*/
        buffer[nbytes] = '\0';
        printf("server: %s\n", buffer);
    }

    return (void *)0;

}


int main(int argc, char **argv)
{

    struct sockaddr_in server_addr;     /*struct sockaddr_in是在头文件<arpa/inet.h>中定义*/

    int sockfd;
    int ret;
    unsigned int sin_size;
    pthread_t tid;
    char buff[SENDBUFFERSIZE] = {0};
    char *pbuff = buff;
    int actualsize = 0;
    const char *quit = "quit";
    int sendsize = 0;
    

    if(argc != 3)
    {
        printf("Usage: %s <ip:x.x.x.x> <port>\n", argv[0]);
        return -1;
    }
    
    /*构建服务器地址结构体
     *填充服务器端sockaddr结构
     */
    bzero(&server_addr, sizeof(struct sockaddr_in));
    server_addr.sin_family = AF_INET;
    /*ip地址转换*/
    ret = inet_aton(argv[1], &server_addr.sin_addr);
    if(ret != 1)
    {
        printf("Usage: %s <ip:x.x.x.x> <port>\n", argv[0]);
        return -1;
    }
    server_addr.sin_port = htons(atoi(argv[2]));

    /*1.创建套接字*/
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if(sockfd == -1)
    {
        printf("socket establish error\n");
        return -1;
    }

    /*2.连接服务器*/
    sin_size = sizeof(struct sockaddr);
    ret = connect(sockfd, (struct sockaddr *)(&server_addr), sin_size);
    if(ret == -1)
    {
        close(sockfd);
        printf("connect: %s:%s error\n", argv[1], argv[2]);
        return -1;
    }

    /*3.服务器成功建立连接
     *3.1主线程用于接收客户端终端输入字符，并发送给服务器端。
     *3.2子线程用于接收服务器端数据，打印在终端。
     */

    /*3.2子线程用于接收服务器端数据，打印在终端。*/
    pthread_create(&tid, NULL, client_recv_fun, &sockfd);

    /*3.1主线程用于接收客户端终端输入字符，并发送给服务器端。*/
    while(1)
    {
        /*3.1.1主线程循环接收用户的输入信息，当输入前四个字符是[quit],则结束通话*/
        /*使用fgets函数接收用户的输入，目的是可以接受空格等字符*/
        memset(buff, 0, SENDBUFFERSIZE);      /*接收新字符之前先清空缓冲区*/
        while(1)
        {
            printf("client:");
            if(fgets(buff, SENDBUFFERSIZE-1, stdin) == NULL)
            {
                printf("[system: please input again!]\n");
                continue;
            }
            break;
        }
        
        actualsize = strlen(buff);

        if(strncmp(buff, quit, 4) == 0)
        {
            printf("[system: quit!]\n");
            break;
        }
        pbuff = buff;
        /*3.1.2发送数据*/
        while(1)
        {
            sendsize = send(sockfd, pbuff, actualsize, 0);
            if(sendsize == -1)
            {
                printf("[system: send error!]\n");
                break;
            }
            if(sendsize == actualsize)
            {
                break;
            }
            if(sendsize < actualsize)
            {
                pbuff += sendsize;
                actualsize -= sendsize;
                continue;
            }
        }
        
    }

    close(sockfd);
    return 0;

}


